import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.*;
import java.awt.*;
import java.io.*;
import java.util.HashSet;
import java.util.Set;

public class HighLightKeywordsDemo {

    public static void main(String[] args) {

        JFrame frame = new JFrame();
        MutableAttributeSet attr = new SimpleAttributeSet();
        StyleConstants.setFontSize(attr, 16);
/*        StyleConstants.setBold(attr,true);*/
        StyleConstants.setFontFamily(attr,"微软雅黑");
        JTextPane editor = new JTextPane();
        editor.setCharacterAttributes(attr,true);
        editor.getDocument().addDocumentListener(new SyntaxHighlighter(editor));


        JScrollPane js=new JScrollPane(editor);
        frame.getContentPane().add(js);

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();

        int width = (int) (screenSize.width / 1.2);
        int height = (int) (screenSize.height / 1.2);
        frame.setSize(width, height);
        frame.setLocation((screenSize.width / 2) - (width / 2),
                (screenSize.height / 2) - (height / 2));
        frame.setMinimumSize(new Dimension((int) (screenSize.width / 4),
                (int) (screenSize.height / 4)));
        frame.setVisible(true);

    }
}



/**

 * 当文本输入区的有字符插入或者删除时, 进行高亮.

 *

 * 要进行语法高亮, 文本输入组件的document要是styled document才行. 所以不要用JTextArea. 可以使用JTextPane.

 *

 * @author Biao

 *

 */

class SyntaxHighlighter implements DocumentListener {

    private Set<String> keywords;

    private Style keywordStyle;

    private Style normalStyle;

    private Style nameStyle;



    public SyntaxHighlighter(JTextPane editor) {

        // 准备着色使用的样式

        keywordStyle = ((StyledDocument) editor.getDocument()).addStyle("Keyword_Style", null);

        normalStyle = ((StyledDocument) editor.getDocument()).addStyle("Normal_Style", null);

        nameStyle = ((StyledDocument) editor.getDocument()).addStyle("Name_Style", null);

        StyleConstants.setForeground(keywordStyle, Color.RED);
        StyleConstants.setForeground(normalStyle, Color.BLACK);
        StyleConstants.setForeground(nameStyle, Color.GREEN);

        String names = "彭健初 李彦文 邓伟谋 周继林 刘国荣 刘杰 曾祥文 王寄忠 禹丽君 刘迟辉 吴喜波 吴正平 曾海军 张玉伟 肖军 刘召书 戴建民 黄国平 龙晓涛 徐迪仁 赵焕 罗文卫 王谦 伍鹤群 高英 刘建斌 周群义 李志鸿 王文成 聂永红 童松闾 龙轶群 郭超群 王理丽 张建飞 康伏卫 李斌涛 颜国芬 肖国良 付朝晖 李建中 王升平 曹季和 高德华 孟跃红";

        // 准备关键字
        keywords = new HashSet<String>();
        File file = new File("./names.txt");
        if(file.exists() && file.isFile()){
            String readStr = readStr(file);
            System.out.println("从配置文件names.txt中读取需要处理的名册");
            if(null != readStr && readStr.length() > 0){
                names = readStr;
            }
            System.out.println("names:" + names);
        }else{
            System.out.println("无法读取"+file.getAbsolutePath()+"/names.txt,使用默认的名册:" + names);
        }

        String[] nameArray = names.split(" ");
        for (String s : nameArray) {
            keywords.add(s);
        }

    }

    private String readStr(File file) {
        try {
            BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
            return br.readLine();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }











    @Override

    public void changedUpdate(DocumentEvent e) {

    }



    @Override

    public void insertUpdate(DocumentEvent e) {

        try {
            SwingUtilities.invokeLater(new ColouringTask((StyledDocument) e.getDocument(),keywords,keywordStyle,normalStyle));
        } catch (Exception e1) {
            e1.printStackTrace();
        }

    }



    @Override

    public void removeUpdate(DocumentEvent e) {

        try {
            SwingUtilities.invokeLater(new ColouringTask((StyledDocument) e.getDocument(),keywords,keywordStyle,normalStyle));
        } catch (Exception e1) {
            e1.printStackTrace();
        }
    }



    /**

     * 完成着色任务

     *

     * @author Biao

     *

     */

    private class ColouringTask implements Runnable {

        private StyledDocument doc;
        private Set<String> keywords;
        private Style keywordStyle;
        private Style normalStyle;


        public ColouringTask(StyledDocument doc, Set<String> keywords, Style keywordStyle, Style normalStyle) {
            this.doc = doc;
            this.keywords = keywords;
            this.keywordStyle =  keywordStyle;
            this.normalStyle = normalStyle;
        }

        @Override
        public void run() {

            try {
                // 这里就是对字符进行着色
                int length = doc.getLength();
                for(int i = 0; i < length; i++){
                    String zi = doc.getText(i,1);
                    int size = isRendered(i, zi);
                    if(size > 1){
                        i=i+(size-1);
                    }
                }
            } catch (Exception e) {}
            }

        private int isRendered(int i, String zi) throws BadLocationException {
            boolean may = false;

            //先判断是否有完全匹配的,完全匹配则不着色
            for (String keyword : keywords) {
                if(keyword.startsWith(zi)){
                    may = true;
                    String word = doc.getText(i,keyword.length());
                    if(word.equalsIgnoreCase(keyword)){
                        doc.setCharacterAttributes(i, keyword.length(), nameStyle, false);
                        return keyword.length();
                    }
                }
            }

            if(may){
                doc.setCharacterAttributes(i, 1, keywordStyle, false);
                return 1;
            }else{
                doc.setCharacterAttributes(i, 1, normalStyle, false);
            }
            return 1;
        }

    }

}
